空物件模式利用一個沒有實質行為的空物件來統一客戶端程式的操作行為。
大家去日本旅遊時曾經注意過日本的販賣機嗎?日本的販賣機非常有趣,有些會用空的包裝來展示商品樣品。初次見到時可能會感到困惑,為什麼要放空瓶子在販賣機裡呢?但仔細一想,若是用實際商品當作樣品,可能會面臨保存期限的問題;而如果不展示樣品,一旦商品售完,顧客也無法知道原先販賣的是什麼。這個空瓶子就如同空物件模式中的空物件,透過沒有實際行為的物件,巧妙地解決了許多問題。
大家在定義變數時,應該經常用 null
或 undefined
作為初始化之前的預設值。使用變數時,往往需要加上額外的判斷邏,以確保變數已經完成初始化。這樣的邏輯一多,會增加不必要的複雜性,也會造成閱讀上的不便。
想像一款電動遊戲,裡面的角色可以裝備武器來攻擊敵人。我們可以使用空物件模式讓角色穿戴”空武器”,省去一些麻煩的檢查。
定義一個武器介面,武器必須具備一個攻擊方法。
interface Weapon {
attack(): void;
}
定義兩個具體的武器類別。劍類別可以用劍攻擊敵人,沒有武器類別則什麼都不會做。
class Sword implements Weapon {
attack() {
console.log("Attacking the enemy with a sword!");
}
}
class NoWeapon implements Weapon {
attack() {
console.log("Do nothing");
}
}
定義角色類別。角色在初始狀態下沒有裝備武器,可以通過 setWeapon
方法為角色裝備一個武器。
class Character {
private weapon: Weapon;
constructor() {
this.weapon = new NoWeapon();
}
setWeapon(weapon: Weapon) {
this.weapon = weapon;
}
attack() {
this.weapon.attack();
}
}
測試角色的行為。
class CharacterTestDriver {
static main() {
const hero = new Character();
const sword = new Sword();
hero.attack();
hero.setWeapon(sword);
hero.attack();
}
}
CharacterTestDriver.main();
首先,角色預設裝備了 "空武器",因此第一次攻擊不會有任何效果。接著,當角色裝備了劍後,角色將會成功攻擊敵人。
空物件是沒有實質操作的具體物件,主要用來避免使用 null
或 undefined
導致的檢查和例外處理。空物件和其他具體類別擁有相同的介面,客戶端可以使用相同的方式處理它們,而不必添加明確地空值檢查。
https://github.com/chengen0612/design-patterns-typescript/blob/main/patterns/other/null-object.ts